//  文件不超过200秒 可以不做视频分割处理
package main

import (
	"bufio"
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	//	"log"
	"errors"
	ffprobe "github.com/vansante/go-ffprobe"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

type Storage struct {
	baseName         string
	baseNum          int
	baseMap          map[string]string
	baseChan         chan string
	dirPath          string
	serqueueName     string // 服务器发送队列
	cliqueueName     string //客户端发送队列
	mqUserName       string
	mqPassword       string
	mqIp             string
	mqPort           string
	baseFile         *os.File
	baseFileName     string
	baseFileDir      string // 下载的文件存储路径(分解后的文件)
	basePicDir       string // 生成文件的存储路径
	hostWanIP        string
	hostName         string
	baseShell        string
	downLoadDir      string //下载的原始文件的保存路径
	upLoadDir        string //  合成后的文件
	taskInputDir     string //task读文件的目录
	taskOutputDir    string // task合成后的数据
	downLoadFileName string //下载后文件名
	segmentDuration  int    //分割文件的大小
	fileWidth        int
	fileHeight       int
	fileDuration     string
	fileCodecName    string
	taskStatus       string
}

func InitStorage() *Storage {

	return &Storage{

		baseMap:  make(map[string]string),
		baseChan: make(chan string, 100000),
	}

}

// RunScript 执行一个名为 的脚本
func RunScript(strShell string) error {
	cmd := exec.Command("/bin/bash", strShell)

	// 运行命令，并获取其输出
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("执行脚本时发生错误: %v, 输出: %s", err, output)
	}

	fmt.Println(time.Now(), "脚本输出:", string(output))
	return nil
}

// SplitVideo 使用 ffmpeg 按关键帧切割视频
// inputFile 是输入的视频文件名
// segmentDuration 是每个视频段的时长（秒）
// outputPath 是切割后的视频文件存储路径


// getVideoDuration 获取视频的总时长（秒）
func getVideoDuration(inputFile string) (int, error) {
	cmd := exec.Command("ffprobe", "-v", "error", "-show_entries", "format=duration",
		"-of", "default=noprint_wrappers=1:nokey=1", inputFile)

	out, err := cmd.StdoutPipe()
	if err != nil {
		return 0, err
	}

	if err := cmd.Start(); err != nil {
		return 0, err
	}

	scanner := bufio.NewScanner(out)
	scanner.Scan()
	durationStr := scanner.Text()

	duration, err := strconv.ParseFloat(strings.TrimSpace(durationStr), 64)
	if err != nil {
		return 0, err
	}

	if err := cmd.Wait(); err != nil {
		return 0, err
	}

	return int(duration), nil
}

// RemoveContents 删除指定目录下的所有文件和子目录
func (s *Storage) RemoveContents(dirPath string) error {
	// 打开指定的目录
	d, err := os.Open(dirPath)
	if err != nil {
		return err
	}
	defer d.Close()
	// 读取目录内容
	names, err := d.Readdirnames(-1)
	if err != nil {
		fmt.Println(time.Now(), err)
		return err
	}

	// 遍历目录内容并删除
	for _, name := range names {
		err = os.RemoveAll(filepath.Join(dirPath, name))
		if err != nil {
			return err
		}
	}

	return nil
}


// printFilesInDir 递归地打印指定目录及其子目录下的所有文件
func (s *Storage) ScanList(dir string) {
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() {
			fmt.Println(time.Now(), "扫描文件列表", path)
			s.baseChan <- path
		}

		return nil
	})
	s.baseChan <- "over"
}

func (s *Storage) RunTask(data string) (err1 error) {

	// 删除图片生成的临时目录

	err := s.RemoveContents(s.basePicDir)
	if err != nil {
		fmt.Println(time.Now(), "无法删除临时文件", s.basePicDir)
		return err
	}
	// 删除分割文件后的临时目录
	err = s.RemoveContents(s.taskInputDir)
	if err != nil {
		fmt.Println(time.Now(), "无法删除临时文件", s.taskInputDir)
		return err
	}

	err = s.RemoveContents(s.taskOutputDir)
	if err != nil {
		fmt.Println(time.Now(), "无法删除临时文件", s.taskOutputDir)
		return err
	}


	//获取文件名
	tokens := strings.Split(data, "/")
	s.downLoadFileName = tokens[len(tokens)-1]
	// 删除分割文件后的临时目录
	err = os.Remove(s.upLoadDir + "/" + s.downLoadFileName)

	if err != nil {
		fmt.Println(time.Now(), "无法删除临时文件", s.upLoadDir+"/"+s.downLoadFileName)
	}

	fmt.Println(time.Now(), "开始调用程序视频加水印")
	tmptime1 := time.Now().Unix()

	//   删除多余临时文件

	//开始调用SHELL
	err = RunScript(s.baseShell)
	if err != nil {
		fmt.Println(time.Now(), "错误:", err)
		return err

	} else {

		fmt.Println(time.Now(), "完成视频加水印", data)

	}
	tmptime2 := time.Now().Unix()

	tmpruntime := tmptime2 - tmptime1
	fmt.Println(time.Now(), "---------当前任务运行时间为----------------|", tmpruntime)


	return nil

}


//  API  接受参数
type RequestData struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	Code string `json:"code"`
}

func (s *Storage) GetVideoMetadata(filePath string) (err error) {

// 下载文件到指定目录








//开始检测文件
	file, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	// 设置超时，以防 ffprobe 命令花费太长时间
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 获取文件的元数据
	metadata, err := ffprobe.GetProbeDataContext(ctx, filePath)
	if err != nil {
		return err
	}

	//检查文件的分辨率 编码格式 时间长度

	for _, stream := range metadata.Streams {
		// 检查是否为视频流
		if stream.CodecType == "video" {
			s.fileWidth = stream.Width
			s.fileHeight = stream.Height
			s.fileDuration = stream.Duration
			s.fileCodecName = stream.CodecName
		}

	}

	fmt.Println(time.Now(), "上传文件", filePath, "相关参数", s.fileWidth, s.fileHeight, s.fileDuration, s.fileCodecName)

	if s.fileWidth != 1920 || s.fileHeight != 1080 {

		return errors.New("分辨率不匹配数据文分辨率 " + strconv.Itoa(s.fileWidth) + ":" + strconv.Itoa(s.fileHeight) + " 系统支持1920:1080")
	}

	if s.fileCodecName != "h264" {

		return errors.New("文件的编码格式不匹配  " + s.fileCodecName + " 系统支持h264")
	}

	t1, _ := strconv.ParseFloat(s.fileDuration, 64)
	if t1 > 60 {

		return errors.New("文件的时间长度不匹配   " + s.fileDuration + "  系统支持时间不超过60秒")
	}








	// 水印的字符串写 .txt文件







	return nil
}

// API的接口机器
func (s *Storage) ApiServer() {

	r := gin.Default()

	r.POST("/submit", func(c *gin.Context) {
		var requestData RequestData

		if err := c.ShouldBindJSON(&requestData); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if s.taskStatus != "waiting" {

			c.JSON(http.StatusOK, gin.H{
				"message": "队列已满 ",
			})

			  return 
		}

		s.taskStatus = "runing"

		// 处理接收到的数据

		//  获取文件信息

		err := s.GetVideoMetadata(s.downLoadDir + "/" + requestData.Name)
		if err != nil {

			c.JSON(http.StatusOK, gin.H{
				"message": "数据错误",
				"data":    err.Error(),
			})
			s.taskStatus = "waiting"
			return

		}

		// 文件检查完毕 开始运行加水印

		err = s.RunTask(s.downLoadDir + "/" + requestData.Name)
		if err != nil {

			c.JSON(http.StatusOK, gin.H{
				"message": "数据错误",
				"data":    err.Error(),
			})
			s.taskStatus = "waiting"
			return

		}

		s.taskStatus = "waiting"

		c.JSON(http.StatusOK, gin.H{
			"message": "数据接收成功开始处理数据 ",
			"data":    requestData,
		})

	})

	r.Run("0.0.0.0:80") // 默认监听并在 0.0.0.0:8080 上启动服务

}

func main() {
	Storage := InitStorage()
	Storage.basePicDir = "pic/tmp"
	Storage.baseFileDir = "data/input_videos/videos_0421/input_video"
	Storage.baseShell = "run_encoder.sh"
	Storage.taskInputDir = "data/input_videos/videos_0421/input_video"
	Storage.taskOutputDir = "data/output_results/results_0421/encoded_videos"
	Storage.downLoadDir = "download"
	Storage.upLoadDir = "upload"
	Storage.taskStatus = "waiting"
	// 开始启动web接口
	Storage.ApiServer()

}
